/**
 * Created by splendourbell on 2017/8/1.
 */

import Gravity from "./Gravity"
import AView from "./AView"
import ASize from "./ASize"
import ARect from "./ARect"

const MeasureSpec_UNSPECIFIED = 0
const MeasureSpec_EXACTLY = 1
const MeasureSpec_AT_MOST = 2

class MeasureSpec {
    constructor(size = 0, mode = MeasureSpec_UNSPECIFIED) {
        this.size = size
        this.mode = mode
    }
}

export const NSLineBreakMode = {
    WordWrapping: 0,
    CharWrapping: 1,
    Clipping: 2,
    TruncatingHead: 3,
    TruncatingTail: 4,
    TruncatingMiddle: 5
}
Object.freeze(NSLineBreakMode)

export const NSTextAlignment = {
    Left: 0,
    Center: 1,
    Right: 2,
    Justified: 3,
    Natural: 4,
}
Object.freeze(NSTextAlignment)

const MIN_VALUE = -999999
const MAX_VALUE = 999999

export default class ATextView extends AView {

    constructor() {
        super()
        this._text = ""
        this.textColor = "#000"
        this.textSize = "18px"
        this.font = "sans-serif"
        this.ellipsize = NSLineBreakMode.WordWrapping
        this.textAlignment = NSTextAlignment.Left
        this.height = MIN_VALUE
        this.width = MIN_VALUE
        this.maxWidth = MAX_VALUE
        this.maxHeight = MAX_VALUE
        this.minWidth = 0
        this.minHeight = 0
        this.typeface = "normal"
        this.textStyle = "" //bold|italic
        this.shadowColor = undefined
        this.shadowDx = 0
        this.shadowDy = -3
        this.shadowRadius = 0
        this.lines = -1
        this.maxLines = MAX_VALUE
        this.minLines = 1
        this.lineSpacingExtra = 2
        this.gravity = Gravity.TOP | Gravity.LEFT
        this.maxLength = MAX_VALUE

        this.padding = {top: 0, left: 0, bottom: 0, right: 0}
    }

    onDraw(context : CanvasRenderingContext2D, rect : ARect) {
        super.onDraw(context, rect)

        context.fillStyle = this.textColor
        context.textBaseline = "hanging"

        let font = this.textSize + ' ' + this.font

        let text = this._text
        if(this._text.length > this.maxLength) {
            text = this._text.substr(0, this.maxLength)
        }
        this.stringBoundInRectWithSize(text, font, rect.size, context)

        context.font = font

        let offY = rect.y
        let offx = rect.x

        let delta = 18 + this.lineSpacingExtra
        this.lineAttrs.forEach((line)=>{

            switch(this.textAlignment) {
                case NSTextAlignment.Center:
                    offx = rect.x + (rect.w - line.width)/2
                    break;
                case NSTextAlignment.Right:
                    offx = rect.x + (rect.w - line.width)
                    break
            }

            context.fillText(line.text, offx, offY)
            offY += delta
        })
    }

    onMeasure(widthSpec: MeasureSpec, heightSpec: MeasureSpec, context : CanvasRenderingContext2D) {

        let padding = this.padding;
        let computeWidth = padding.left + padding.right
        let computeHeight = padding.top + padding.bottom

        let width = 0
        let height = 0

        let maxAvailableWidth = widthSpec.size
        let maxAvailableHeight = heightSpec.size

        let textWidthSpec = new MeasureSpec()
        let textHeightSpec = new MeasureSpec()

        if (maxAvailableWidth >= this.maxWidth) {
            textWidthSpec.mode = MeasureSpec_AT_MOST
            maxAvailableWidth = this.maxWidth
        }

        if (maxAvailableWidth <= this.minWidth) {
            textWidthSpec.mode = MeasureSpec_EXACTLY;
            maxAvailableWidth = this.minWidth;
        }

        if (maxAvailableHeight >= this.maxHeight) {
            textHeightSpec.mode = MeasureSpec_AT_MOST;
            maxAvailableHeight = this.maxHeight;
        }

        if (maxAvailableHeight <= this.minHeight) {
            textHeightSpec.mode = MeasureSpec_EXACTLY;
            maxAvailableHeight = this.minHeight;
        }

        maxAvailableWidth -= computeWidth;
        maxAvailableHeight -= computeHeight;

        maxAvailableWidth = Math.max(0, maxAvailableWidth);
        maxAvailableHeight = Math.max(0, maxAvailableHeight);

        if (MeasureSpec_EXACTLY == widthSpec.mode) {
            width = widthSpec.size;
            textWidthSpec.mode = MeasureSpec_EXACTLY;
        }
        else {
            textWidthSpec.mode = MeasureSpec_AT_MOST;
        }

        textWidthSpec.size = maxAvailableWidth;

        if (MeasureSpec_EXACTLY == heightSpec.mode) {
            height = heightSpec.size;
            textHeightSpec.mode = MeasureSpec_EXACTLY;
        }
        else {
            textHeightSpec.mode = MeasureSpec_AT_MOST;
        }

        textHeightSpec.size = maxAvailableHeight;

        let textMeasuredSize = this.textOnMeasure(textWidthSpec, textHeightSpec, context);

        computeWidth += textMeasuredSize.width;
        computeHeight += textMeasuredSize.height;

        if (MeasureSpec_EXACTLY != widthSpec.mode) {
            widthSpec.mode = MeasureSpec_EXACTLY;
            width = computeWidth;
        }

        if (MeasureSpec_EXACTLY != heightSpec.mode) {
            heightSpec.mode = MeasureSpec_EXACTLY;
            height = computeHeight;
        }

        this.measuredDimensionRaw = new ASize(width, height)
    }

    textOnMeasure(widthSpec: MeasureSpec, heightSpec: MeasureSpec, context : CanvasRenderingContext2D) {

        if (this.height >= 0) {
            heightSpec.mode = MeasureSpec_EXACTLY;
            heightSpec.size = this.height;
        }
        else if (MeasureSpec_EXACTLY != heightSpec.mode) {
            heightSpec.mode = MeasureSpec_AT_MOST;
        }

        if (this.width >= 0) {
            widthSpec.mode = MeasureSpec_EXACTLY;
            widthSpec.size = this.width;
        }
        else if (MeasureSpec_EXACTLY != widthSpec.mode) {
            widthSpec.mode = MeasureSpec_AT_MOST;
        }

        let contentSize = new CGSize();


        /*


         NSMutableAttributedString* attributedString = (NSMutableAttributedString *)self.textAttributedString;
         if(attributedString)
         {
         CGRect bounds   = CGRectZero;
         CGSize sizeTmp  = CGSizeMake(widthSpec.size, heightSpec.size);
         if (_needStrBounds || CGSizeEqualToSize(sizeTmp, _strBaseSize))
         {
         _needStrBounds  = false;
         _strBaseSize    = sizeTmp;
         NSMutableDictionary *cachDict = [NSMutableDictionary dictionary];
         [attributedString enumerateAttribute:(NSString*)kCTParagraphStyleAttributeName inRange:NSMakeRange(0, [attributedString length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {

         NSMutableParagraphStyle* paragraphStyle = [value mutableCopy];
         if ([paragraphStyle lineBreakMode] != NSLineBreakByWordWrapping)
         {
         cachDict[NSStringFromRange(range)] = @([paragraphStyle lineBreakMode]);
         [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
         }

         [attributedString removeAttribute:(NSString*)kCTParagraphStyleAttributeName range:range];
         [attributedString addAttribute:(NSString*)kCTParagraphStyleAttributeName value:paragraphStyle range:range];
         }];

         bounds = [self _attibuteString:attributedString boundIngRectWithSize:sizeTmp];

         if (cachDict.count)
         {
         [attributedString enumerateAttribute:(NSString*)kCTParagraphStyleAttributeName inRange:NSMakeRange(0, [attributedString length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
         NSNumber *lineBreakMode = cachDict[NSStringFromRange(range)];
         if (lineBreakMode)
         {
         NSMutableParagraphStyle* paragraphStyle = [value mutableCopy];
         paragraphStyle.lineBreakMode = [lineBreakMode integerValue];
         [attributedString removeAttribute:(NSString*)kCTParagraphStyleAttributeName range:range];
         [attributedString addAttribute:(NSString*)kCTParagraphStyleAttributeName value:paragraphStyle range:range];
         }
         }];
         }

         _strBounds = bounds;

         }
         else
         {
         bounds = _strBounds;
         }

         contentSize = bounds.size;

         if(MeasureSpec_EXACTLY != widthSpec.mode)
         {
         widthSpec.size = bounds.size.width;
         widthSpec.mode = MeasureSpec_EXACTLY;
         }

         if(MeasureSpec_EXACTLY != heightSpec.mode)
         {
         heightSpec.size = MIN(bounds.size.height, heightSpec.size);
         heightSpec.mode = MeasureSpec_EXACTLY;
         }
         contentSize.height = MIN(contentSize.height, heightSpec.size);
         }
         else
         {
         if(MeasureSpec_EXACTLY != widthSpec.mode)
         {
         widthSpec.mode = MeasureSpec_EXACTLY;
         widthSpec.size = 0;
         }
         if(MeasureSpec_EXACTLY != heightSpec.mode)
         {
         heightSpec.mode = MeasureSpec_EXACTLY;
         heightSpec.size = 0;
         }
         }

         //assert(MeasureSpec_EXACTLY == widthSpec.mode && MeasureSpec_EXACTLY == heightSpec.mode);

         let measuredSize = new ASize(widthSpec.size, heightSpec.size);
         self.textLabel.viewParams.measuredSize = measuredSize;
         _textLabelContentSize   = contentSize;
         return measuredSize;
         */
    }

    stringBoundInRectWithSize(string : string, font : string, size : ASize, context : CanvasRenderingContext2D) : ARect {

        context.font = font
        context.textBaseline = 'hanging'

        let length = string.length
        let preStrObj = {}

        let lineAttrs = []

        let start = 0
        for(let index = 0; index < length; index++) {

            let sublen = index - start + 1
            let subStr = string.substr(start, sublen)
            let width = context.measureText(subStr).width

            if(width > size.width && sublen > 1) {
                lineAttrs.push(preStrObj)
                preStrObj = {}
                start = index
            }
            else {
                preStrObj.index = index
                preStrObj.text = subStr
                preStrObj.width = width
            }
        }

        if(preStrObj.text) {
            lineAttrs.push(preStrObj)
        }

        this.lineAttrs = lineAttrs
    }
//
// - (CGRect)_attibuteString:(NSAttributedString *)attStr boundIngRectWithSize:(CGSize)csize
// {
//     NSInteger maxLine   = 0;
//     NSInteger minLine   = 0;
//
//     CGRect bounds       = CGRectZero;
//     if (_lines == -1)
// {
//     if (_maxLines == 0 && _minLines == 0)
// {
//     bounds = [attStr boundingRectWithSize:CGSizeMake(csize.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil];
// }
// else
// {
//     maxLine = MAX(maxLine, _maxLines);
//     minLine = MIN(minLine, _minLines);
// }
// }
// else
// {
//     if (_lines == 0)
//     {}
//     else if (_lines == 1)
//     {
//         bounds = [attStr boundingRectWithSize:csize options:0 context:nil];
//     }
//     else
//     {
//         maxLine = minLine = _lines;
//         if (_maxLines > 0 || _minLines > 0)
//         {
//             maxLine = MIN(maxLine, _maxLines);
//             minLine = MAX(minLine, _minLines);
//         }
//     }
// }
//
// if (maxLine > 0 || minLine > 0)
// {
//     CGMutablePathRef pathRef        = CGPathCreateMutable();
//     CGRect pathRect                 = CGRectMake(0, 0, csize.width, CGFLOAT_MAX);
//     CGPathAddRect(pathRef, NULL, pathRect);
//     CTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr);
//     CTFrameRef frameRef             = CTFramesetterCreateFrame(framesetterRef, CFRangeMake(0, attStr.length), pathRef, nil);
//
//     CFArrayRef lines        = CTFrameGetLines(frameRef);
//     NSInteger lineCount     = CFArrayGetCount(lines);
//
//     if (minLine > lineCount)
//     {
//         bounds = [self _appendEnterCount:minLine - lineCount originAttStr:attStr cacluteSize:csize];
//     }
//     else if (maxLine < lineCount)
//     {
//         bounds = [self _getLastLineMaxY:maxLine - 1 lines:lines originAttStr:attStr baseWidth:csize.width];
//     }
//     else
//     {
//         bounds = [attStr boundingRectWithSize:CGSizeMake(csize.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil];
//     }
//
//     CFRelease(pathRef);
//     CFRelease(frameRef);
//     CFRelease(framesetterRef);
// }
// return bounds;
// }

    set text(text: ?string) {
        this._text = text
    }

    get text(): ?string {
        return this._text
    }
}

